﻿/**
 * @file BaseThread.h
 * @author swq (swq123459@qq.com)
 * @brief
 * @version 0.1
 * @date 2020-12-04
 *
 * @copyright Copyright (c) 2020
 *
 */
#ifndef _BASETHREAD_H_
#define _BASETHREAD_H_

#include <condition_variable>
#include <exception>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>

typedef enum { RUN_FOREVER, RUN_ONCE } THRERD_MODE;

class CBaseThread {
  using ThreadType = std::thread;
  using CondType = std::condition_variable;
  using MutexType = std::mutex;
  using ThreadPtrType = std::unique_ptr<ThreadType>;

public:
  CBaseThread(void) : _thread_mode(RUN_FOREVER){};
  ~CBaseThread() {
    if (_destroy)
      return;
    this->uninit();
  }

  void init(void *parent = NULL, THRERD_MODE thread_mode = RUN_FOREVER) {
    _parent = parent;
    _thread_mode = thread_mode;
    on_init();
    _thraed_ptr = std::make_unique<ThreadType>([this]() { this->run(); });
    if (!_thraed_ptr)
      throw(std::runtime_error("init thread error, null thraed poiter"));
  };

  void uninit(void) {
    _destroy = true;
    _cond.notify_one();
    if (this->isAlive())
      _thraed_ptr->join();
    on_uninit();
  };

  virtual void run(void) {
    on_start();
    do {
      on_process();
    } while (!_destroy && (RUN_FOREVER == _thread_mode) && !_will_destroy);
    on_shutdown();
  };

  bool isAlive() const {
    if (_thraed_ptr)
      return _thraed_ptr->joinable();
    return false;
  }

  void will_destroy() { _will_destroy = true; }

  THRERD_MODE get_thread_mode(void) { return _thread_mode; }

protected:
  virtual void on_init(void){};
  virtual void on_uninit(void){};
  virtual void on_start(void){};
  /**
   * @brief Thread run event handling (Do not block it)
   */
  virtual void on_process(void){};

  virtual void on_shutdown(void){};

protected:
  void *_parent = nullptr;
  volatile bool _destroy = false;
  volatile bool _will_destroy = false;
  THRERD_MODE _thread_mode;
  ThreadPtrType _thraed_ptr = nullptr;
  MutexType _monitor;
  CondType _cond;
};

using fun_trhead = std::function<void()>;
class CGBThread;
using CGBThreadPtr = std::unique_ptr<CGBThread>;
class CGBThread : public CBaseThread {
public:
  CGBThread() {}
  ~CGBThread() { shutdown(); }
  bool start(fun_trhead fun) {
    _fun = fun;
    init(); //启动线程
    return true;
  }

  void shutdown() { uninit(); }

  void on_process(void) override {
    if (_fun)
      _fun();
  }

private:
  fun_trhead _fun = nullptr;
};

#endif // _BASETHREAD_H_
